.data


# Strings for console output / prompts 
splash:         .asciiz "\n  MIPS ASM ID3 TAG EDITOR\n  v .1  May 2007\n  Created By : Nick Lafrenz, Mike Nicholson, Brad Collins\n------------------------------------------------\n\n"
menu:           .asciiz "\nPlease select from the following options.\n(1) Display ID3 tag information\n(2) Display Extended ID3 tag information\n(3) Modify ID3 information\n(4) Open New File\n(5) Save file (write changes to disk)\n(0) Exit\n :: "
modmenu:        .asciiz "\n(1) Modify Entry \n(2) Delete Entry\n(3) Return to menu\n :: "
pfile:          .asciiz "Please enter the filename (leave blank and press enter to exit) "
pstring:        .asciiz "Please enter the new information string "
pframe:         .asciiz "Please select a frame to modify "
psuccess:       .asciiz "File was opened successfully\n"
pfailure:       .asciiz "ERROR : File failed to open\n\n"
strnotfound:    .asciiz " Not Found "
strnewline:     .asciiz "\n"


# numerical constants
filenamesize:   .word 128
negone:         .word -1
taglength:      .word 1024  # working tag actual length (MUST BE CHANGED PROGRAMATICALLY)
wtpe1:          .word 0x31455054    # artist/group
wtalb:          .word 0x424c4154    # album/movie/show title (album title)
wtit2:          .word 0x32544954    # title/songname
wtlen:          .word 0x4e454c54    # audio length in ms
wtrck:          .word 0x4b435254    # track number
wtyer:          .word 0x52455954    # year of recording (numeric ascii)
wtpub:          .word 0x42555054    # publisher
wtcon:          .word 0x4e4f4354    # content type / genre
wtit1:          .word 0x31544954    # content group (to level category, not genre)
wtit3:          .word 0x33544954    # subtitle/description refinement
wtbpm:          .word 0x4d504254    # bpm (integer as numerical string)
wtcom:          .word 0x4d4f4354    # composer
wtdat:          .word 0x54414454    # date of recording (DDMM format)
wtenc:          .word 0x434e4554    # encoded by
wtext:          .word 0x54584554    # lyricist/text writer (seperated with /)
wtflt:          .word 0x544c4654    # file type
wtime:          .word 0x454d4954    # recording time (HHMM format)
wtlan:          .word 0x4e414c54    # language
wtpos:          .word 0x534f5054    # part of set 
wtsiz:          .word 0x5a495354    # audio file size (in bytes)


# string constants
stalb:          .asciiz "TALB"  # album/movie/show title (album title)
stbpm:          .asciiz "TBPM"  # bpm (integer as numerical string)
stcom:          .asciiz "TCOM"  # composer
stcon:          .asciiz "TCON"  # content type / genre
stdat:          .asciiz "TDAT"  # date of recording (DDMM format)
stenc:          .asciiz "TENC"  # encoded by
stext:          .asciiz "TEXT"  # lyricist/text writer (seperated with /)
stflt:          .asciiz "TFLT"  # file type
stime:          .asciiz "TIME"  # recording time (HHMM format)
stit1:          .asciiz "TIT1"  # content group (to level category, not genre)
stit2:          .asciiz "TIT2"  # title/songname
stit3:          .asciiz "TIT3"  # subtitle/description refinement
stlan:          .asciiz "TLAN"  # language
stlen:          .asciiz "TLEN"  # audio length in ms
stpe1:          .asciiz "TPE1"  # artist/group
stpos:          .asciiz "TPOS"  # part of set 
stpub:          .asciiz "TPUB"  # publisher
strck:          .asciiz "TRCK"  # track number
stsiz:          .asciiz "TSIZ"  # audio file size (in bytes)
styer:          .asciiz "TYER"  # year of recording (numeric ascii)

rtalb:          .asciiz "Album :          " 
rtbpm:          .asciiz "BPM :            " 
rtcom:          .asciiz "Composer :       " 
rtcon:          .asciiz "Genre :          "  
rtdat:          .asciiz "Recording Date : " 
rtenc:          .asciiz "Encoded By :     " 
rtext:          .asciiz "Lyricist :       " 
rtflt:          .asciiz "File Type :      " 
rtime:          .asciiz "Recording Time : " 
rtit1:          .asciiz "Content Group :  "  
rtit2:          .asciiz "Song Title :     " 
rtit3:          .asciiz "Song Subtitle :  " 
rtlan:          .asciiz "Language :       " 
rtlen:          .asciiz "Track Length :   " 
rtpe1:          .asciiz "Artist :         "     
rtpos:          .asciiz "Part of Set :    " 
rtpub:          .asciiz "Publisher :      " 
rtrck:          .asciiz "Track Number :   " 
rtsiz:          .asciiz "File Size :      " 
rtyer:          .asciiz "Recording Year : " 

p1:             .asciiz "(1) "
p2:             .asciiz "(2) "
p3:             .asciiz "(3) "
p4:             .asciiz "(4) "
p5:             .asciiz "(5) "
p6:             .asciiz "(6) "
p7:             .asciiz "(7) "
p8:             .asciiz "(8) "
p9:             .asciiz "(9) "
p10:             .asciiz "(10) "
p11:             .asciiz "(11) "
p12:             .asciiz "(12) "
p13:             .asciiz "(13) "
p14:             .asciiz "(14) "
p15:             .asciiz "(15) "
p16:             .asciiz "(16) "
p17:             .asciiz "(17) "
p18:             .asciiz "(18) "
p19:             .asciiz "(19) "
p20:             .asciiz "(20) "

# storage
filesize:       .word 0         # original file size as bytes read in during read
filename:       .space 128
strbuf:         .space 1024
origsize:       .word 0         # original file size - full ID3 tag size
buffer:         .space 10485760 # ASCII encoded (10MB)
workingTag:     .space 524288   # allocate a big chunk(512k) of storage for the new tag 
frmbuf:         .space 1036     #buffer for new frames

# id3 header flags
FLAGunsync:     .space 1
FLAGexthdr:     .space 1
FLAGexprmt:     .space 1        # I dont think well even use this
FLAGfooter:     .space 1

# other tag info
TAGsize:        .word 0
TAGexthdrsize:  .word 0
TAGframesum:    .word 0


.text
main:

# File Input
#   prompt for file input and then input the mp3 to memory (if it exists)

    # print splash screen
    la      $a0, splash
    li      $v0, 4
    syscall

    # print filename prompt
    la      $a0, pfile      #prompt for filename input
    li      $v0, 4
    syscall
    
    # get filename
    la      $a0, filename
    lw      $a1, filenamesize
    li      $v0, 8
    syscall
    
    # remove line feed character from input file
    la      $a0, filename
    lw      $a1, filenamesize
    jal     crremove    
    lbu     $t0, filename
    addi    $t0, $t0, -0x0a
    beq     $t0, $0, exit

    # open file
    la      $a0, filename
    li      $a1, 0x0082         # Read/write file input
    li      $v0, 13
    syscall
    move    $s0, $v0        # file descriptor

    # check if file open was successful
    lw      $t0, negone
    beq     $s0, $t0, fail
    li      $v0, 4
    la      $a0, psuccess
    syscall

    # read in the whole file
    move    $a0, $s0        # Move the file descriptor to $a0
    la      $a1, buffer
    li      $a2, 10485760   # 10 MB file input size limit
    li      $v0, 14
    syscall
    sw      $v0, filesize   
.globl  decodeCall
decodeCall:
    la      $a0, buffer
    jal     decodeID3
    
    # generate origsize
    lw      $t0, filesize
    addi    $t0, $t0, -10   # subtract ID3 header
    lw      $t1, TAGsize
    sub     $t0, $t0, $t1
    lb      $t1, FLAGfooter
    beq     $t1, $0, nofoot
    addi    $t0, $t0, -10    # subtract footer if it exists
nofoot:
    sw      $t0, origsize   

printmenu:
    la      $a0, menu
    li      $v0, 4
    syscall                 # print the menu
    li      $v0, 5
    syscall                 # get the choice
    # $v0 contains input integer
    li      $t0, 0
    beq     $v0, $t0, exit
    li      $t0, 1
    beq     $v0, $t0, callprinttag
    li      $t0, 2
    beq     $v0, $t0, callprintexttag
    li      $t0, 3
    beq     $v0, $t0, callmodify
    li      $t0, 4
    beq     $v0, $t0, callnewfile
    li      $t0, 5
    beq     $v0, $t0, callsavefile
    j       printmenu

    # main subroutine calls
callprinttag:
    jal     printtag
    j       printmenu
callprintexttag:
    jal     printexttag
    j       printmenu
callmodify:
    jal     modifyframemenu
    j       printmenu
callnewfile:
    j       newfile
callsavefile:
    jal     savefile
    j       newfile 


newfile:
    move    $a0, $s0
    li      $v0, 16
    syscall                 # close the file
    j       main

fail:
    la      $a0, pfailure       
    li      $v0, 4
    syscall                 # output failure information
    j       newfile
    
exit:
    move    $a0, $s0
    li      $v0, 16
    syscall                 # close file
    li      $v0, 10
    syscall                 # exit program






# Decode Routine 
# Parses header info and copys the ID3 tag to the location in memory called 'working tag' 
#
# It will do more once we decide how to go about constructing the new tag
#
# no arguments
#
# what I'm doing with registers
# t0: file pointer for mp3 file
# t1: working register for current tag data
# t2: comparison register
# 

.globl decodeID3
decodeID3:
    # push all the registers we will modify to the stack
    addi    $sp, $sp, -4
    sw      $ra, 0($sp)
    addi    $sp, $sp, -4
    sw      $t0, 0($sp)
    addi    $sp, $sp, -4
    sw      $t1, 0($sp)
    addi    $sp, $sp, -4
    sw      $t2, 0($sp)
    addi    $sp, $sp, -4
    sw      $t3, 0($sp)
    addi    $sp, $sp, -4
    sw      $t4, 0($sp)
    addi    $sp, $sp, -4
    sw      $t5, 0($sp)

     # zero out old flags
    move    $t1, $0
    la      $t4, FLAGunsync
    sb      $t1, 0($t4)
    la      $t4, FLAGexthdr
    sb      $t1, 0($t4)
    la      $t4, FLAGexprmt
    sb      $t1, 0($t4)
    la      $t4, FLAGfooter
    sb      $t1, 0($t4)
    la      $t4, TAGexthdrsize
    sw      $t1, 0($t4)
.globl br1  
    la      $t0, buffer     #copy file pointer to t0
    lw      $t1, 0($a0)     #load first word of file
    li      $t4, 0x00FFFFFF
    #lui    $t4, 0x00FF
    #addi   $t2, $t2, 0xFFFF
    and     $t1, $t1, $t4
    lui     $t2, 0x33       #load t2 with ID3 in proper endian order
    addi    $t2, $t2, 0x4449
    bne     $t1, $t2, decodeEXIT    # if the first three byes of the file are ID3 then it has an ID3v2.x.x tag

    lw      $t1, 0($t0)     # working with id3 version 2.4.0 or lower, get the first byte of the major revision
    srl     $t1, $t1, 24 
    addi    $t2, $0, 0x04
    bgt     $t1, $t2, decodeEXIT
        
    addi    $t0, $t0, 4
    lb      $t1, 0($t0)
    add     $t2, $0, $0
    bne     $t1, $t2, decodeEXIT
    
    addi    $t0, $t0, 1
    lb      $t1, 0($t0)     #being processing flags
    srl     $t1, $t1, 4
    
    addi    $t2, $0, 0x1
    andi    $t4, $t1, 0x8
    srl     $t4, $t4, 3 
    bne     $t2, $t4, unsyncNOTSET
    la      $t5, FLAGunsync
    add     $t4, $0, 0x1
    sw      $t4, 0($t5) 
    
unsyncNOTSET:
    andi    $t4, $t1, 0x4
    srl     $t4, $t4, 2
    bne     $t2, $t4, exthdrNOTSET
    la      $t5, FLAGexthdr
    add     $t4, $0, 0x1
    sw      $t4, 0($t5)

exthdrNOTSET:
    andi    $t4, $t1, 0x02
    srl     $t4, $t4, 1
    bne     $t2, $t4, exprmtNOTSET
    la      $t5, FLAGexprmt
    addi    $t4, $0, 0x1
    sw      $t4, 0($t5)
    
exprmtNOTSET:
    andi    $t4, $t1, 0x01
    bne     $t2, $t4, footerNOTSET
    la      $t5, FLAGfooter
    addi    $t4, $0, 0x1
    sw      $t4, 0($t5)

footerNOTSET:
    
    addi    $t0, $t0, 1
    add     $a0, $t0, $0
    jal     pseudolw
    add     $a0, $0, $v0
    jal     SSINTtoUINT
    la      $t5, TAGsize
    sw      $v0, 0($t5)
    
    la      $t2, FLAGexthdr         #if the ext hdr is present calculate its size
    lb      $t2, 0($t2)
    
    beq     $t2, $0, NoExtHdr
    addi    $t0, $t0, 4
    add     $a0, $t0, $0
    jal     pseudolw
    add     $a0, $v0, $0
    jal     SSINTtoUINT
    la      $t5, TAGexthdrsize
    sw      $v0, 0($t5)
NoExtHdr:

    la      $t3, workingTag         # begin copying tag into workingTag
    la      $t0, buffer         # reload file pointer
    
    la      $t2, TAGsize            #calculate total tag size
    lw      $t2, 0($t2)
    addi    $t2, $t2, 10
    la      $t4, FLAGfooter
    lb      $t4, 0($t4)
    beq     $t4, $0, beginDecodeCopyLoop
    addi    $t2, $t2, 10
beginDecodeCopyLoop:
    lb      $t1, 0($t0)
    sb      $t1, 0($t3)
    addi    $t3, $t3, 1
    addi    $t0, $t0, 1
    addi    $t2, $t2, -1
    bne     $t2, $0, beginDecodeCopyLoop
    jal     sumframesize
decodeEXIT:  #CLEANUP AND EXIT
    lw      $t5, 0($sp)
    addi    $sp, $sp, 4
    lw      $t4, 0($sp)
    addi    $sp, $sp, 4
    lw      $t3, 0($sp)
    addi    $sp, $sp, 4
    lw      $t2, 0($sp)      # Pop registers
    addi    $sp, $sp, 4
    lw      $t1, 0($sp)
    addi    $sp, $sp, 4
    lw      $t0, 0($sp)
    addi    $sp, $sp, 4
    lw      $ra, 0($sp)
    addi    $sp, $sp, 4
    jr      $ra



# Decode Synchsafe Integers
#
# In some parts of an ID3 tag are store as synch safe integers. For example,
# When parsing the header we do not yet know if a synchronization scheme is used
# So integers in the header are stored as 32 bit synchsafe integers.
# 
# In a synchsafe int, the eighth bit of each byte (bit 7) is zeroed, therefore a 32
# bit synchsafe int can only store 28 bits of data.  for example 255 represented as
# a synchsafe int is 0b0000000101111111, therefore we must translate these to 
# regular 32 but uints
# Parameters
# $a0 32 bit synch safe int
# Return:
# $v0 28 bit unsigned int (2MSB's zeroed)

SSINTtoUINT:
    #push modified registers
    addi    $sp, $sp, -4
    sw      $ra, 0($sp)
    addi    $sp, $sp, -4        #make room on stack
    sw      $t0, 0($sp)

        # do the actual decoding of the ssint
    jal     revreg
    #add    $a0, $0, $v0
    andi    $t0, $a0, 0x7F      # mask all but lowest 7 bits
    move    $v0, $t0
    andi    $t0, $a0, 0x7F00    # mask out middle 7 bits
    srl     $t0, $t0, 1         # get rid of synch bit (actually msb of last byte)
    add     $v0, $v0, $t0
    move    $t0, $a0
    srl     $t0, $t0, 16        # move 2 upper bytes to replace the lower bytes
    andi    $t0, $t0, 0x7F      # move mask out lower 7 bytes
    sll     $t0, $t0, 14        # we've now discarded two bits of data (synch bits)
    add     $v0, $v0, $t0
    move    $t0, $a0
    srl     $t0, $t0, 24        # ok its not the most efficient way to zero out all but the upper byte
    sll     $t0, $t0, 21        # but it works  
    add     $v0, $v0, $t0       # and we're done
    
    # pop modified registers and return
    lw      $t0, 0($sp) 
    addi    $sp, $sp, 4
    lw      $ra, 0($sp)
    addi    $sp, $sp, 4
    jr      $ra  

# UINTtoSSINT
# 
# This routine does the exact opposite of SSINTtoUINT
#
# Arugments:
#   a0  28bit uint
# Return:
#   v0 32bit sync safe int
UINTtoSSINT:
    #push modified registers
    addi    $sp, $sp, -4
    sw      $ra, 0($sp)
    addi    $sp, $sp, -4
    sw      $t0, 0($sp)
    addi    $sp, $sp, -4
    sw      $t1, 0($sp)

    li      $t0, 0x0FE00000
    and     $v0, $t0, $a0
    sll     $v0, $v0, 3

    li      $t0, 0x001FC000
    and     $t1, $t0, $a0
    sll     $t1, $t1, 2
    or      $v0, $v0, $t1

    li      $t0, 0x00003F80
    and     $t1, $t0, $a0
    sll     $t1, $t1, 1
    or      $v0, $v0, $t1

    li      $t0, 0x0000007F
    and     $t1, $t0, $a0
    or      $v0, $v0, $t1
    
    add     $a0, $v0, $0
    jal     revreg
    add     $v0, $a0, $0
 
    lw      $t1, 0($sp)
    addi    $sp, $sp, 4
    lw      $t0, 0($sp)
    addi    $sp, $sp, 4
    lw      $ra, 0($sp)
    addi    $sp, $sp, 4
    jr      $ra    


# addFrame
#
# Takes a frame ID and pointer to a string buffer containing the new string and
# writes it into the working tag
#
# Arguments:
#   a0: FrameID pointer (to the hex version)
addFrame:
    
    addi    $sp, $sp, -4
    sw      $ra, 0($sp)
    addi    $sp, $sp, -4
    sw      $t0, 0($sp)
    addi    $sp, $sp, -4
    sw      $t1, 0($sp)
    addi    $sp, $sp, -4
    sw      $t2, 0($sp)
    addi    $sp, $sp, -4
    sw      $t3, 0($sp)
    addi    $sp, $sp, -4
    sw      $t4, 0($sp)
    addi    $sp, $sp, -4
    sw      $t5, 0($sp)
    la      $t0, frmbuf    # clear frame buffer
    li      $t1, 1036
frmbufCLR:
    sb      $0, 0($t0)
    addi    $t0, 1
    addi    $t1, -1
    bne     $t1, $0, frmbufCLR
    
    la      $t3, frmbuf         # insert frame ID
    lw      $t4, 0($a0)
    sw      $t4, 0($t3)         # frame ID stored
    
    la      $t0, strbuf         
    li      $t5, 0x0A
br1:    addi     $t0, $t0, 1
addFrmCalcSz:                   # calculate size of string in string buffer
    addi    $t2, $t2, 1         # the size must be at least one byte, hence the add before the test
    lb      $t1, 0($t0)
    add     $t0, $t0, 1
    beq     $t1, $t5, exitCalcSz 
    beq     $t1, $0, exitCalcSz 
    j       addFrmCalcSz
exitCalcSz:
    add     $a0, $t2, $0
    jal     UINTtoSSINT         # translate this to a ssint
    addi    $t3, $t3, 4         # write ssint into bytes 4-7 in frame buffer
    sw      $v0, 0($t3)

    addi    $t3, $t3, 4
    sb      $0, 0($t3)             # insert zeroed flag bytes
    addi    $t3, $t3, 1
    sb      $0, 0($t3)
    addi    $t3, $t3, 1
    la      $t0, strbuf
    add     $t4, $t2, $0
cpyStrToFrmBuf:   
    lb      $t1, 0($t0)         #copy string from str buf to frame buf
    sb      $t1, 0($t3)
    addi    $t0, $t0, 1  
    addi    $t3, $t3, 1
    addi    $t4, $t4, -1
    bne     $t4, $0, cpyStrToFrmBuf

    addi    $t2, $t2, 10        # make sure theres enough space in the padding
    addi    $t0, $0, 10         # t0 contains total size - footer
    addi    $t1, $0, 10         # t1 contians total size - footer - padding
    la      $t3, TAGexthdrsize
    lw      $t3, 0($t3)
    add     $t1, $t1, $t3
    la      $t3, TAGframesum
    lw      $t3, 0($t3)
    add     $t1, $t1, $t3
    la      $t3, TAGsize
    lw      $t3, 0($t3)
    add     $t0, $t0, $t3

    sub     $t3, $t0, $t1       # t3 should contain padding size

    bgt     $t3, $t2, addFrmNoShift
    la      $t3, workingTag
    add     $a0, $t3, $t0
    addi    $a1, $0, 10
    add     $a2, $t2, $0
    jal     byteShiftFW 
addFrmNoShift:
    la      $t3, workingTag
    add     $t1, $t1, $t3
    la      $t0, frmbuf
    add     $t4, $t2, $0
frmCpyLoop:
    lb      $t5, 0($t0)             # overwrite padding with framebuffer contents
    sb      $t5, 0($t1)
    addi    $t0, $t0, 1
    addi    $t1, $t1, 1
    addi    $t4, $t4, -1
    bne     $t4, $0, frmCpyLoop
    
    la      $t0, TAGframesum        # udpate TAGframesum to include new frame
    lw      $t1, 0($t0)
    add     $t1, $t1, $t2
    sw      $t1, 0($t0)
   
    lw      $t5, 0($sp)
    addi    $sp, $sp, 4
    lw      $t4, 0($sp)
    addi    $sp, $sp, 4
    lw      $t3, 0($sp)
    addi    $sp, $sp, 4
    lw      $t2, 0($sp)
    addi    $sp, $sp, 4
    lw      $t1, 0($sp)
    addi    $sp, $sp, 4
    lw      $ra, 0($sp)
    addi    $sp, $sp, 4
    lw      $ra, 0($sp)
    addi    $sp, $sp, 4 
    jr      $ra


# delFrame
#
# Takes a frame descriptor, finds that frame and deletes it from the working tag, shifting any
# frames following back and readjusting the padding size
#
# Arguments
# $a0 contains address of frameID to be deleted 
#
delFrame:
    # push all the registers we will modify to the stack
    addi    $sp, $sp, -4
    sw      $ra, 0($sp)
    addi    $sp, $sp, -4
    sw      $t0, 0($sp)
    addi    $sp, $sp, -4
    sw      $t1, 0($sp)
    addi    $sp, $sp, -4
    sw      $t2, 0($sp)

    jal     findframe
    li      $t1, -1
    beq     $v1, $t1, delFrameExit
    addi    $v1, $v1, 10      # Calculate actual length including header
    
    la      $t0, TAGframesum
    lw      $t0, 0($t0)
    la      $t1, TAGexthdrsize
    lw      $t1, 0($t1)
    add     $t0, $t0, $t1
    la      $t1, workingTag
    add     $t0, $t0, $t1
    addi    $t0, $t0, 10        #start address of padding should be in t0

    add     $t1, $v0, $v1       #calculate end address of deleled frame
    sub     $a1, $t0, $t1       # number of bytes to be shifted = frame end address - padding start
    add     $a0, $v0, $0
    add     $a0, $a0, $v1
    add     $a2, $v1, $0
    la      $t1, TAGframesum    #adjust TAGframesum to reflect changes
    lw      $t0, 0($t1)
    sub     $t0, $t0, $v1
    sw      $t0, 0($t1)
    jal     byteShiftBack       #shift the bytes, this will destroy the data
    
    la      $t1, workingTag
    add     $a0, $t0, $t1       # modified framesum is still in t0,
    addi    $a0, $a0, 10
    la      $t1, TAGexthdrsize
    lw      $t1, 0($t1)
    add     $a0, $a0, $t1       # $a0 should contain padding start addy now
    add     $a1, $v1, $0        # amount of padding that needs written = deleted frame size
    jal     writePad
   
    # cleanup and exit 
delFrameExit:
    lw      $t2, 0($sp)      # Pop registers
    addi    $sp, $sp, 4
    lw      $t1, 0($sp)
    addi    $sp, $sp, 4
    lw      $t0, 0($sp)
    addi    $sp, $sp, 4
    lw      $ra, 0($sp)
    addi    $sp, $sp, 4
    jr      $ra


# writePad
#
# Write padding in to replace a deleted frame 
#
# Arguments
#   a0: address to start writing padding
#   a1: number of padding bytes to write
writePad:
    ble     $a1, $0, writePadExit
writePadLoop:
    sb      $0, 0($a0)
    addi    $a0, $a0, 1
    addi    $a1, $a1, -1
    bne     $a1, $0, writePadLoop
writePadExit:
    jr      $ra


# byteShiftFW
#
# Shifts a specified number of bytes starting at a specified address fowrads
#
# Arguments:
#   a0: start address of bytes to be shifted
#   a1: number of bytes to be shfited
#   a2: distance to shift foward
byteShiftFW:
    addi    $sp, $sp, -4
    sw      $ra, 0($sp)
    addi    $sp, $sp, -4
    sw      $t0, 0($sp)
    addi    $sp, $sp, -4
    sw      $t1, 0($sp)
    addi    $sp, $sp, -4
    sw      $t2, 0($sp)
    addi    $sp, $sp, -4
    sw      $t3, 0($sp)
    addi    $sp, $sp, -4
    sw      $t4, 0($sp)

    add     $t0, $a0, $a1       # t0 is the last byte to be shited
    add     $t1, $t0, $a2       # t1 is destination pointer
    add     $t3, $a1, $0
byteShiftFWLoop:
    lb      $t4, 0($t0)
    sb      $t4, 0($t1)
    addi    $t0, $t0, -1
    addi    $t1, $t1, -1
    addi    $t3, $t3, -1
    bne     $t3, $0, byteShiftFWLoop

    lw      $t4, 0($sp)
    addi    $sp, $sp, 4
    lw      $t3, 0($sp)
    addi    $sp, $sp, 4
    lw      $t2, 0($sp)
    addi    $sp, $sp, 4
    lw      $t1, 0($sp)
    addi    $sp, $sp, 4
    lw      $t0, 0($sp)
    addi    $sp, $sp, 4
    lw      $ra, 0($sp)
    addi    $sp, $sp, 4
    jr      $ra

# byteShiftBack
#
# This routine shifts a specified number of bytes starting at a specified address backwards
# That is, starting at $a0, shift $a1 bytes $a2 bytes backwards
#
# Aguments:
#   a0: start address of bytes to be shifted
#   a1: number of bytes to be shifted
#   a2: distance to shift back
#
#
byteShiftBack:
    addi    $sp, $sp, -4
    sw      $ra, 0($sp)
    addi    $sp, $sp, -4
    sw      $t0, 0($sp)
    addi    $sp, $sp, -4
    sw      $t1, 0($sp)
   
    beq     $a1, $0, byteSBExit
    sub     $t0, $a0, $a2       #t0 stores the destination pointer

byteShiftLoop:
    lb      $t1, 0($a0)
    sb      $t1, 0($t0)
    addi    $a0, $a0, 1
    addi    $t0, $t0, 1
    addi    $a1, $a1, -1
    bne     $a1, $0, byteShiftLoop

byteSBExit:
    lw      $t1, 0($sp)
    addi    $sp, $sp, 4
    lw      $t0, 0($sp)
    addi    $sp, $sp, 4
    lw      $ra, 0($sp)
    addi    $sp, $sp, 4
    jr      $ra


# Frame Finding
#
# Returns the beginning address of the given frame (at the title e.g. TIT2)
#       Format : [TIT2][SIZE][FL][ ... info ... ]
#                ^        ^
#          v0 contains the first ptr (caret), v1 is the size indicated by the second caret     
#
# Parameters
# $a0 contains address of memory location for frame title to be looked up 
#   (e.g. wtit1 contains TIT1 in hex) .  Note that this isn't the string constant,
#   because (1) those are null terminated and (2) those aren't word aligned 
#   (making lw difficult)
# 
# Return
# $v0 contains the address of the new frame (the beginning of the frame TAG, so 10 bytes
#     before the information in the frame)
# $v1 contains the length of the new frame (as defined in the frame, so total - 10 byte header)

findframe:  
    addi    $sp, $sp, -4
    sw      $a0, 0($sp)
    addi    $sp, $sp, -4
    sw      $t0, 0($sp) 
    addi    $sp, $sp, -4
    sw      $t1, 0($sp)
    addi    $sp, $sp, -4
    sw      $t2, 0($sp) 
    addi    $sp, $sp, -4
    sw      $t3, 0($sp)
    addi    $sp, $sp, -4
    sw      $t4, ($sp)  
    addi    $sp, $sp, -4
    sw      $t5, 0($sp)
    addi    $sp, $sp, -4
    sw      $ra, 0($sp)
    
    lw      $t0, ($a0)              # should contain all 4 bytes/chars of the frame title 
    la      $t4, workingTag
    lw      $t2, taglength
    li      $t5, 10                 # length of current frame/until next frame
    lw      $t1, TAGexthdrsize
    add     $t5, $t5, $t1
findloop:
    add     $t4, $t4, $t5           # add frame length (to next frame)
    sub     $t2, $t2, $t5           # remove the frame length from the remaining tag length 
    move    $a0, $t4
    jal     pseudolw                # load word starting at $t4 into $t3
    move    $t3, $v0
    addi    $t4, $t4, 4             # move past frame title (4 bytes/chars)
    move    $a0, $t4
    jal     pseudolw                # get length field (32 bit int)
    move    $a0, $v0
    jal     SSINTtoUINT             # reverse the length register for proper byte order
    move    $t5, $v0                
    beq     $t0, $t3, framefound    # if the current title matches the search title
    beq     $t3, $0, framenotfound  # if the frame title is blank, we're into the tag padding
    ble     $t2, $0, framenotfound  # we've not found the title by the end of the tag
    addi    $t4, $t4, 6             # skip length and tags (6 bytes)
    addi    $t2, $t2, -10           # remove the 10 frame header bytes from tag length
    j       findloop

framenotfound:
    li      $v0, -1
    li      $v1, -1
    j       endfindframe
    
framefound:
    addi    $t4, $t4, -4            # move back to beginning of matching title (back 4 bytes)
    move    $v0, $t4
    move    $v1, $t5

endfindframe:
    lw      $ra, 0($sp)
    addi    $sp, $sp, 4
    lw      $t5, 0($sp)
    addi    $sp, $sp, 4
    lw      $t4, 0($sp)
    addi    $sp, $sp, 4
    lw      $t3, 0($sp)
    addi    $sp, $sp, 4
    lw      $t2, 0($sp)
    addi    $sp, $sp, 4
    lw      $t1, 0($sp)
    addi    $sp, $sp, 4
    lw      $t0, 0($sp)
    addi    $sp, $sp, 4
    lw      $a0, 0($sp)
    addi    $sp, $sp, 4
    jr      $ra





# Carriage Return Removal
#
# Removes the trailing carriage return from a string.
# This routine uses a loop, because we may not be sure of the true size of the string, 
#   only the size of the space it fits in.
#
# Parameters
# $a0 contains the address of the memory location containing the string to be modified
# $a1 contains the length of the string (in bytes/chars) being modified

crremove:   
    addi    $sp, $sp, -4
    sw      $a0, 0($sp)
    addi    $sp, $sp, -4
    sw      $a1, 0($sp)
    addi    $sp, $sp, -4
    sw      $t0, 0($sp)
    addi    $sp, $sp, -4
    sw      $t1, 0($sp)
    addi    $sp, $sp, -4    
    sw      $ra, 0($sp)

    li      $t1, 0x0A           # carriage return in hex
    add     $a0, $a0, $a1       # start at end of string (remove right most CR)
        
rmloop:

    addi    $a0, $a0, -1        # move backwards through the string to only remove trailing CR
    addi    $a1, $a1, -1        
    lb      $t0, ($a0)          
    beq     $a1, $0, endrmloop  
    bne     $t0, $t1, rmloop    
    sb      $0, ($a0)           # replace instance of 0x0a with 0x00

endrmloop:
    lw      $ra, 0($sp)
    addi    $sp, $sp, 4
    lw      $t1, 0($sp)
    addi    $sp, $sp, 4
    lw      $t0, 0($sp)
    addi    $sp, $sp, 4
    lw      $a1, 0($sp)
    addi    $sp, $sp, 4
    lw      $a0, 0($sp)
    addi    $sp, $sp, 4
    jr      $ra
  





# psuedolw
#
# Loads a register with 4 bytes that are not word aligned
#
# Parameters
# $a0 contains starting memory address
# 
# Return
# $v0 contains the newly loaded word

pseudolw:
    addi    $sp, $sp, -4
    sw      $t0, ($sp)

    move    $t0, $0
    move    $v0, $0

    lbu     $t0, 3($a0)         # copy byte into temp register
    or      $v0, $t0, $v0       # add the byte from t0 into correct location of dest reg
    sll     $v0, $v0, 8         # shift register to align for next byte 
    lbu     $t0, 2($a0)         # repeat for all 4 bytes
    or      $v0, $t0, $v0
    sll     $v0, $v0, 8
    lbu     $t0, 1($a0)
    or      $v0, $t0, $v0
    sll     $v0, $v0, 8
    lbu     $t0, 0($a0)
    or      $v0, $t0, $v0
    
    lw      $t0, ($sp)
    addi    $sp, $sp, 4
    jr      $ra





# Reverse Register
#
# Reverses register $a0's byte format (useful for incorrectly byte oriented
#   string representation of integers) 

revreg:
    addi    $sp, $sp, -4
    sw      $t0, ($sp)
    addi    $sp, $sp, -4
    sw      $t1, ($sp)
    addi    $sp, $sp, -4
    sw      $ra, ($sp)

    # basically, move LSB into a0, shift left, move next LSB in...etc.
    move    $t0, $a0
    move    $a0, $0
    andi    $t1, $t0,0x00ff
    sll     $t1, $t1, 24
    or      $a0, $t1, $a0
    andi    $t1, $t0, 0xff00
    sll     $t1, $t1, 8
    or      $a0, $t1, $a0
    li      $t1, 0x00ff
    sll     $t1, $t1, 16
    and     $t1, $t0, $t1
    srl     $t1, $t1, 8
    or      $a0, $t1, $a0
    li      $t1, 0xff00
    sll     $t1, $t1, 16
    and     $t1, $t0, $t1
    srl     $t1, $t1, 24
    or      $a0, $t1, $a0
    
    lw      $ra, ($sp)
    addi    $sp, $sp, 4
    lw      $t1, ($sp)
    addi    $sp, $sp, 4
    lw      $t0, ($sp)
    addi    $sp, $sp, 4
    jr      $ra




# Print ID3 Contents
# 
# Prints (some) of the contents of the ID3 tag.

printtag:
    addi    $sp, $sp, -4
    sw      $ra, ($sp)
    addi    $sp, $sp, -4
    sw      $a0, ($sp)  
    
    la      $a0, rtpe1      # print readable title of field (Artist)
    li      $v0, 4
    syscall                 
    la      $a0, wtpe1      
    jal     printframe      # print contents of artist frame (ascii formatted)

    la      $a0, rtalb
    li      $v0, 4
    syscall
    la      $a0, wtalb
    jal     printframe
    
    la      $a0, rtit2
    li      $v0, 4
    syscall
    la      $a0, wtit2
    jal     printframe
    
    la      $a0, rtlen
    li      $v0, 4
    syscall
    la      $a0, wtlen
    jal     printframe

    la      $a0, rtrck
    li      $v0, 4
    syscall
    la      $a0, wtrck
    jal     printframe
    
    la      $a0, rtyer
    li      $v0, 4
    syscall
    la      $a0, wtyer
    jal     printframe
    
    la      $a0, rtpub
    li      $v0, 4
    syscall
    la      $a0, wtpub
    jal     printframe
    
    lw      $a0, ($sp)
    addi    $sp, $sp, 4
    lw      $ra, ($sp)
    addi    $sp, $sp, 4
    jr      $ra






# Print Extended ID3 Contents
# 
# Prints all of the handled contents of the ID3 tag.

printexttag:
    addi    $sp, $sp, -4
    sw      $ra, ($sp)
    addi    $sp, $sp, -4
    sw      $a0, ($sp)  
    
    la      $a0, rtpe1      # print readable title of field (Artist)
    li      $v0, 4
    syscall                 
    la      $a0, wtpe1      
    jal     printframe      # print contents of artist frame (ascii formatted)

    la      $a0, rtalb
    li      $v0, 4
    syscall
    la      $a0, wtalb
    jal     printframe
    
    la      $a0, rtit2
    li      $v0, 4
    syscall
    la      $a0, wtit2
    jal     printframe
    
    la      $a0, rtlen
    li      $v0, 4
    syscall
    la      $a0, wtlen
    jal     printframe

    la      $a0, rtrck
    li      $v0, 4
    syscall
    la      $a0, wtrck
    jal     printframe
    
    la      $a0, rtyer
    li      $v0, 4
    syscall
    la      $a0, wtyer
    jal     printframe
    
    la      $a0, rtpub
    li      $v0, 4
    syscall
    la      $a0, wtpub
    jal     printframe
   
    la      $a0, rtcon
    li      $v0, 4
    syscall
    la      $a0, wtcon
    jal     printframe

    la      $a0, rtit1
    li      $v0, 4
    syscall
    la      $a0, wtit1
    jal     printframe

    la      $a0, rtit3
    li      $v0, 4
    syscall
    la      $a0, wtit3
    jal     printframe

    la      $a0, rtbpm
    li      $v0, 4
    syscall
    la      $a0, wtbpm
    jal     printframe

    la      $a0, rtcom
    li      $v0, 4
    syscall
    la      $a0, wtcom
    jal     printframe

    la      $a0, rtdat
    li      $v0, 4
    syscall
    la      $a0, wtdat
    jal     printframe

    la      $a0, rtenc
    li      $v0, 4
    syscall
    la      $a0, wtenc
    jal     printframe

    la      $a0, rtext
    li      $v0, 4
    syscall
    la      $a0, wtext
    jal     printframe

    la      $a0, rtflt
    li      $v0, 4
    syscall
    la      $a0, wtflt
    jal     printframe

    la      $a0, rtime
    li      $v0, 4
    syscall
    la      $a0, wtime
    jal     printframe

    la      $a0, rtlan
    li      $v0, 4
    syscall
    la      $a0, wtlan
    jal     printframe

    la      $a0, rtpos
    li      $v0, 4
    syscall
    la      $a0, wtpos
    jal     printframe

    la      $a0, rtsiz
    li      $v0, 4
    syscall
    la      $a0, wtsiz
    jal     printframe


    lw      $a0, ($sp)
    addi    $sp, $sp, 4
    lw      $ra, ($sp)
    addi    $sp, $sp, 4
    jr      $ra





# Print Frame Contents
#
# Prints the contents of a given frame to the console
#
# Parameters
# $a0 contains word to find (eg wtalb)

printframe:
    addi    $sp, $sp, -4
    sw      $ra, ($sp)
    addi    $sp, $sp, -4
    sw      $t0, ($sp)  
    
    li      $t0, -1

    jal     findframe       # we already know $a0 is the word (eg wtalb)

    beq     $v0, $t0, noframeexit       # if -1, frame is missing
    beq     $v1, $t0, noframeexit       # if -1, frame is missing

    addi    $v0, 10         # move past frame header
    move    $a0, $v0        # pointer to beginning of frame         
    move    $a1, $v1        # stores 32 bit length of frame (total length - 10)
    jal     strtobuf        # copy the contents to the strbuf for output

    la      $a0, strbuf
    li      $v0, 4
    syscall                 # output the strbuf
    la      $a0, strnewline
    li      $v0, 4
    syscall
    
    j       printframeexit

noframeexit:
    # possibly add special text for missing info
    la      $a0, strnewline
    li      $v0, 4
    syscall

printframeexit:
    lw      $t0, ($sp)
    addi    $sp, $sp, 4
    lw      $ra, ($sp)
    addi    $sp, $sp, 4
    jr      $ra
    






# Parse Temp String
#
# Parses a temporary string value out of the ID3 tag, given it's beginning address and length
# Stores said string to memory as a null terminated string for output
#
# Parameters
# $a0 - memory location of start of string
# $a1 - length of string in bytes
#
# Stores the outputable string in strbuf

strtobuf:
    addi    $sp, $sp, -4
    sw      $t0, ($sp)
    addi    $sp, $sp, -4
    sw      $t1, ($sp)
    addi    $sp, $sp, -4
    sw      $t2, ($sp)
    addi    $sp, $sp, -4
    sw      $t3, ($sp)
    addi    $sp, $sp, -4
    sw      $ra, ($sp)

    jal     clrstrbuf
    move    $t0, $a0
    move    $t1, $a1
    la      $t3, strbuf

rmnullloop:                         # removes null ($00) before a string value  
    beq     $t1, $0, strtobufexit
    lbu     $t2, ($t0)              
    addi    $t1, $t1, -1            # decrement length of string counter
    addi    $t0, $t0, 1             # increment pointer in string
    beq     $t2, $0, rmnullloop             
   
    addi    $t1, $t1, 1             # adjust the count, so it doesn't end 1 char early
getstringloop:
    sb      $t2, ($t3)
    lbu     $t2, ($t0)
    addi    $t3, $t3, 1             # increment the pointer to the buffer
    addi    $t0, $t0, 1             # increment the pointer to the string
    addi    $t1, $t1, -1            # decrement the length of string counter
    bne     $t1, $0, getstringloop
    j       strtobufexit

strtobufexit:
    lw      $ra, ($sp)
    addi    $sp, $sp, 4
    lw      $t3, ($sp)
    addi    $sp, $sp, 4
    lw      $t2, ($sp)
    addi    $sp, $sp, 4
    lw      $t1, ($sp)
    addi    $sp, $sp, 4
    lw      $t0, ($sp)
    addi    $sp, $sp, 4
    jr      $ra





# Clear String Buffer
#
# Zeros out the entire string buffer (strbuf)

clrstrbuf:
    addi    $sp, $sp, -4
    sw      $t0, ($sp)
    addi    $sp, $sp, -4
    sw      $t1, ($sp)
    addi    $sp, $sp, -4
    sw      $ra, ($sp)
    
    la      $t0, strbuf     # pointer to strbuf
    li      $t1, 1024       # string buffer size

clrstrbufloop:
    sb      $0, ($t0)
    addi    $t0, $t0, 1
    addi    $t1, $t1, -1
    bne     $t1, $0, clrstrbufloop

    lw      $ra, ($sp)
    addi    $sp, $sp, 4
    lw      $t1, ($sp)
    addi    $sp, $sp, 4
    lw      $t0, ($sp)
    addi    $sp, $sp, 4
    jr      $ra





# Sum Frame Sizes
#
# Adds together the size of all of the frames in the working tag
#   including the 10 bytes of each frame header (tag+size+flags)
#   but not including the 10 bytes (or more) for the entire tag header
#   and extended header.
#
# Stores the total size to TAGframesum
 
sumframesize:
    addi    $sp, $sp, -4
    sw      $t0, ($sp)
    addi    $sp, $sp, -4
    sw      $t1, ($sp)
    addi    $sp, $sp, -4
    sw      $t2, ($sp)
    addi    $sp, $sp, -4
    sw      $t3, ($sp)
    addi    $sp, $sp, -4
    sw      $t4, ($sp)
    addi    $sp, $sp, -4
    sw      $t5, ($sp)
    addi    $sp, $sp, -4
    sw      $ra, ($sp)
   
    la      $t0, workingTag         # t0 = current pointer into working tag           
    lw      $t1, taglength          # t1 = length of the entire tag, to terminate loop if necessary   
    move    $t3, $0                 # t3 = running total frame size
    li      $t2, 10                 # t2 = length of current frame/until next frame
    lw      $t5, TAGexthdrsize
    add     $t5, $t2, $t5
    move    $t2, $t5
sumframeloop:
    add     $t0, $t0, $t2           # add frame length (to next frame)
    sub     $t1, $t1, $t2           # remove the frame length from the remaining tag length 
    add     $t3, $t3, $t2
    move    $a0, $t0
    jal     pseudolw
    move    $t4, $v0                # t4 = current frame, to check if we're in padding
    addi    $t0, $t0, 4             # move past frame title (4 bytes/chars)
    move    $a0, $t0
    jal     pseudolw                # get length field (32 bit int)
    move    $a0, $v0
    jal     SSINTtoUINT             # reverse the length register for proper byte order and remove synch bits
    move    $t2, $v0            
    beq     $t4, $0, endsumframeloop  # if the frame title is blank, we're into the tag padding
    ble     $t1, $0, endsumframeloop  # we've not found the title by the end of the tag
    addi    $t0, $t0, 6             # skip length and tags (6 bytes)
    addi    $t3, $t3, 10            # add header size of current frame to running total
    j       sumframeloop 

endsumframeloop:
    sub     $t3, $t3, $t5
    sw      $t3, TAGframesum

    lw      $ra, ($sp)
    addi    $sp, $sp, 4
    lw      $t5, ($sp)
    addi    $sp, $sp, 4
    lw      $t4, ($sp)
    addi    $sp, $sp, 4
    lw      $t3, ($sp)
    addi    $sp, $sp, 4
    lw      $t2, ($sp)
    addi    $sp, $sp, 4
    lw      $t1, ($sp)
    addi    $sp, $sp, 4
    lw      $t0, ($sp)
    addi    $sp, $sp, 4
    jr      $ra







# Save File
#
# Writes the modified mp3 back to disk.
# The working tag is written, then the rest of the mp3 from the original file 
#   is appended.
# 
# $s0 should contain the file identifier.  

savefile:
    addi    $sp, $sp, -4
    sw      $ra, ($sp)
    addi    $sp, $sp, -4
    sw      $t0, ($sp)
    addi    $sp, $sp, -4
    sw      $t1, ($sp)
   
    #close
    move    $a0, $s0
    li      $v0, 16
    syscall

    #open
    la      $a0, filename
    li      $a1, 0x0302         #truncate file before writing
    li      $v0, 13
    syscall

    # write working tag to file
    move    $a0, $s0
    la      $a1, workingTag
    lw      $a2, TAGsize
    addi    $a2, $a2, 10
    lb      $t0, FLAGfooter
    beq     $t0, $0, apptagnofoot
    addi    $a2, $a2, 10
apptagnofoot:
    li      $v0, 15
    syscall
    # append mp3 portion of original file
    move    $a0, $s0
    la      $a1, buffer
    lw      $t0, TAGsize
    add     $a1, $a1, $t0       
    addi    $a1, $a1, 10        # point to file after ID3 portion
    lb      $t0, FLAGfooter
    beq     $t0, $0, appnofoot
    addi    $a1, $a1, 10        # add 10 for the footer if it exists (usually not)
appnofoot:
    lw      $a2, origsize       # original file size (minus ID3)
    li      $v0, 15
    syscall
    move    $a0, $s0
    li      $v0, 16
    syscall


    lw      $t1, ($sp)
    addi    $sp, $sp, 4
    lw      $t0, ($sp)
    addi    $sp, $sp, 4
    lw      $ra, ($sp)
    addi    $sp, $sp, 4
    jr      $ra





# Modify Frame Menu
#
# Displays the interface and provides the backend for frame modification

modifyframemenu:
    addi    $sp, $sp, -4
    sw      $ra, ($sp)
    addi    $sp, $sp, -4
    sw      $t0, ($sp)
    addi    $sp, $sp, -4
    sw      $t1, ($sp)

    la      $a0, p1
    li      $v0, 4
    syscall
    la      $a0, rtpe1      # print readable title of field (Artist)
    syscall                 
    la      $a0, wtpe1      
    jal     printframe      # print contents of artist frame (ascii formatted)

    la      $a0, p2
    syscall
    la      $a0, rtalb
    syscall
    la      $a0, wtalb
    jal     printframe
    
    la      $a0, p3
    syscall
    la      $a0, rtit2
    syscall
    la      $a0, wtit2
    jal     printframe
    
    la      $a0, p4
    syscall
    la      $a0, rtlen
    syscall
    la      $a0, wtlen
    jal     printframe

    la      $a0, p5
    syscall
    la      $a0, rtrck
    syscall
    la      $a0, wtrck
    jal     printframe
    
    la      $a0, p6
    syscall
    la      $a0, rtyer
    syscall
    la      $a0, wtyer
    jal     printframe
    
    la      $a0, p7
    syscall
    la      $a0, rtpub
    syscall
    la      $a0, wtpub
    jal     printframe
   
    la      $a0, p8
    syscall
    la      $a0, rtcon
    syscall
    la      $a0, wtcon
    jal     printframe

    la      $a0, p9
    syscall
    la      $a0, rtit1
    syscall
    la      $a0, wtit1
    jal     printframe

    la      $a0, p10
    syscall
    la      $a0, rtit3
    syscall
    la      $a0, wtit3
    jal     printframe

    la      $a0, p11
    syscall
    la      $a0, rtbpm
    syscall
    la      $a0, wtbpm
    jal     printframe

    la      $a0, p12
    syscall
    la      $a0, rtcom
    syscall
    la      $a0, wtcom
    jal     printframe

    la      $a0, p13
    syscall
    la      $a0, rtdat
    syscall
    la      $a0, wtdat
    jal     printframe

    la      $a0, p14
    syscall
    la      $a0, rtenc
    syscall
    la      $a0, wtenc
    jal     printframe

    la      $a0, p15
    syscall
    la      $a0, rtext
    syscall
    la      $a0, wtext
    jal     printframe

    la      $a0, p16
    syscall
    la      $a0, rtflt
    syscall
    la      $a0, wtflt
    jal     printframe

    la      $a0, p17
    syscall
    la      $a0, rtime
    syscall
    la      $a0, wtime
    jal     printframe

    la      $a0, p18
    syscall
    la      $a0, rtlan
    syscall
    la      $a0, wtlan
    jal     printframe

    la      $a0, p19
    syscall
    la      $a0, rtpos
    syscall
    la      $a0, wtpos
    jal     printframe

    la      $a0, p20
    syscall
    la      $a0, rtsiz
    syscall
    la      $a0, wtsiz
    jal     printframe


    la      $a0, pframe
    syscall
    li      $v0, 5
    syscall
    # $v0 contains input
    move    $t1, $v0

    la      $a0, modmenu
    li      $v0, 4
    syscall
    li      $v0, 5
    syscall

    li      $t0, 1
    beq     $v0, $t0, menumod
    li      $t0, 2
    beq     $v0, $t0, menudel
    li      $t0, 3
    beq     $v0, $t0, exitmodify
    j       exitmodify

menumod:
    ble     $t1, $0, exitmodify
    li      $t0, 20
    bgt     $t1, $t0, exitmodify
    addi    $t1, $t1, -1
    li      $t0, 4
    mul     $t1, $t1, $t0         # generate an offset for the choice, since all memory is in order
    
    la      $a0, wtpe1
    add     $a0, $a0, $t1       # should point to the correct word
    move    $t1, $a0
    
    la      $a0, pstring
    li      $v0, 4
    syscall
    la      $a0, strbuf         # buffer
    li      $a1, 1024           # length
    li      $v0, 8
    syscall
    move    $a0, $t1
    jal     delFrame
    move    $a0, $t1
    jal     addFrame
    j       exitmodify

menudel:
    ble     $t1, $0, exitmodify
    li      $t0, 21
    bgt     $t1, $t0, exitmodify
    addi    $t1, $t1, -1
    li      $t0, 4
    mul     $t1, $t1, $t0         # generate an offset for the choice, since all memory is in order
    
    la      $a0, wtpe1
    add     $a0, $a0, $t1       # should point to the correct word
    jal     delFrame
    j       exitmodify
    

    # INSERT CALL TO MODIFICATION FUNCTION HERE
exitmodify:
    lw      $t1, ($sp)
    addi    $sp, $sp, 4
    lw      $t0, ($sp)
    addi    $sp, $sp, 4
    lw      $ra, ($sp)
    addi    $sp, $sp, 4
    jr      $ra
    
